Generic Functions

 

Generic functions allow you to specify different arguments list for an abstract function type. This allows the programmer more flexibility in specifying the argument list for a function.

 

To give an idea of how these functions are used here is an example:

 

double overloaded sqrt(double);

int overloaded sqrt(int);

 

This declares two different functions that will get an automatic name furnished by the compiler. Those functions will be selected at the call site according to their arguments list: if the argument list is a double, the first function will be called and the type of the resulting expression is a double. If an integer is given, the second function will be selected and the resulting type is integer.

 

The exact syntax is:

 

Short form:

 

<return type> overloaded identifier ( argument-list )

 

Example:

double overloaded sqrt(double);

 

The compiler will supply here automatically a name for this function. The name will be constructed from the overloaded identifier and the argument list.

 

Long form:

<return type> overloaded identifier . identifier ( argument-list )

 

Example:

 

double overloaded sqrt.DblSqrt(double);

int overloaded sqrt.IntSqrt(int);

 

The long form allows the programmer to override the automatic name of the function and furnish its own. This is important since it allows for easy interfacing of the software that uses this extension with other software.

 

This extension doesn’t introduce a new keyword. You can still define

 

int overloaded = 0;

 

or

 

int overloaded(int a);

 

or even

 

typedef int *overloaded;

overloaded foo(int a);

 

and this will compile as you would expect. In the last example the typedef definition is used, since overloaded functions can’t have an implicit “int” result: they must be given a full prototype.

 

If you need (for whatever reason) to force the compiler to choose one of the overloaded functions, you should use the long notation and just call the function in question:

 

double overloaded sqrt.DblSqrt(double);

int overloaded sqrt.IntSqrt(int);

 

You can force calling the first function just with:

 

      double s = DblSqrt(4.9);

 

The DblSqrt function will be visible in the current scope after the “overloaded” declaration is seen.

 

Rules for using this extension

·         You can add any number of overloaded arguments lists to an identifier, but once the first call to such a function is generated, it is impossible to add a new definition.

 

For instance :

 

double overloaded sqrt(double);

int overloaded sqrt(int);

int foo(void)

{

   double a = sqrt(2.3);

}

double overloaded sqrt(complex) ;

 

This is an error. All overloaded function definitions must be present when the first call is generated.

·         You must supply the « overloaded » marker at the declaration and at the definition of the function. For instance, it is an error when you write :

double overloaded sqrt(double) ;

double sqrt(double) // error : redefinition of sqrt.

{

}

 

Applications of overloaded functions

 

This extension is very useful for constructors. For instance consider:

typedef struct _Person {

      char *Name;

      int Age;

} Person;

 

Person * overloaded newPerson(void)

{

      return (Person *)malloc(sizeof(Person));

}

 

Person *newPerson(char *name)

{

      Person *result = malloc(sizeof(Person));

      result->Name = name;

      return result;

}

Person *newPerson(char *Name,int age)

{

      Person *result = (Person *)malloc(sizeof(Person));

      result->Name = name;

      result->Age = age;

      return result;

}

 

etc.